其他
抓到 Dubbo 异步调用的小 Bug,再送你一个贡献开源代码的机会
The following article is from 捉虫大师 Author 小楼MrRoshi
最近一个同学说遇到了一个 Dubbo 异步调用的问题,怀疑是个 Bug。提到 Bug 我可就不困了,说不定可以水,哦不...写一篇文章。
问题复现
接口返回类型是 boolean; 同步改为异步调用,返回的 boolean 和预期不符合; boolean 基本类型改成包装类型 Boolean 就能正常返回。
public interface DemoService {
boolean isUser();
Boolean isFood();
}
@Service
public class DemoServiceImpl implements DemoService {
@Override
public boolean isUser() {
System.out.println("server is user : true");
return true;
}
@Override
public Boolean isFood() {
System.out.println("server is food : true");
return true;
}
}
@RestController
public class DemoCallerService {
@Reference(injvm = false, check = false)
private DemoService demoService;
@GetMapping(path = "/isUser")
public String isUser() throws Exception {
BlockingQueue<Boolean> q = new ArrayBlockingQueue<>(1);
RpcContext.getContext().asyncCall(
() -> demoService.isUser()
).handle(
(isUser, throwable) -> {
System.out.println("client is user = " + isUser);
q.add(isUser);
return isUser;
});
q.take();
return "ok";
}
@GetMapping(path = "/isFood")
public String isFood() throws Exception {
BlockingQueue<Boolean> q = new ArrayBlockingQueue<>(1);
RpcContext.getContext().asyncCall(
() -> demoService.isFood()
).handle(
(isFood, throwable) -> {
System.out.println("client is food = " + isFood);
q.add(isFood);
return isFood;
});
q.take();
return "ok";
}
}
// client ...
client is user = false
// server ...
server is user : true
// client ...
client is food = true
// server ...
server is food : true
问题排查
com.alibaba.dubbo.remoting.exchange.support.DefaultFuture#doReceived
断点①为了证明我们的请求进来了; 断点②为了证明进了回调; 断点③为了能从接收到数据包的初始位置开始排查。
sc *.proxy0
jad org.apache.dubbo.common.bytecode.proxy0
//local invoke will return directly
server is user : true
client is user = true
如何修复
public <T> CompletableFuture<T> asyncCall(Callable<T> callable) {
try {
try {
setAttachment(ASYNC_KEY, Boolean.TRUE.toString());
final T o = callable.call();
//local invoke will return directly
if (o != null) {
if (o instanceof CompletableFuture) {
return (CompletableFuture<T>) o;
}
if (injvm()) { // 伪代码
return CompletableFuture.completedFuture(o);
}
} else {
// The service has a normal sync method signature, should get future from RpcContext.
}
} catch (Exception e) {
throw new RpcException(e);
} finally {
removeAttachment(ASYNC_KEY);
}
} catch (final RpcException e) {
// ....
}
return ((CompletableFuture<T>) getContext().getFuture());
}
最后
- EOF -
看完本文有收获?请转发分享给更多人
关注「ImportNew」,提升Java技能
点赞和在看就是最大的支持❤️